import 'dart:isolate';

import 'package:flutter/services.dart';
import 'package:web_socket_channel/web_socket_channel.dart';

import 'esc_command.dart';
import 'flutter_gprinter_platform_interface.dart';
import 'package:easy_isolate/easy_isolate.dart';

typedef SocketDataHandler = void Function(String response);

typedef CallHandler = void Function(dynamic);

void mainHandler(dynamic data, SendPort isolateSendPort) {}

void isolateHandler(
  dynamic data,
  SendPort mainSendPort,
  SendErrorFunction onSendError,
) {
  PrintEvent event = data;
  BackgroundIsolateBinaryMessenger.ensureInitialized(event.token);
  FlutterGprinterPlatform.instance.write(event.commands);
}

class FlutterGprinter {
  final worker = Worker();

  Future<void> init() async {
    await worker.init(mainHandler, isolateHandler, queueMode: true);
  }

  Future<String?> getPlatformVersion() {
    return FlutterGprinterPlatform.instance.getPlatformVersion();
  }

  void addMethodCallHandler(CallHandler handler) {
    FlutterGprinterPlatform.instance.addMethodCallHandler(handler);
  }

  void navUsbDevices() {
    FlutterGprinterPlatform.instance.navUsbDevices();
  }

  void navBTDevices() {
    FlutterGprinterPlatform.instance.navBTDevices();
  }

  void navWifiDevices() {
    FlutterGprinterPlatform.instance.navWifiDevices();
  }

  void autoConnect() {
    FlutterGprinterPlatform.instance.autoConnect();
  }

  void connectUSB(String pathName) {
    FlutterGprinterPlatform.instance.connectUSB(pathName);
  }

  void connectNet(String ipAddress) {
    FlutterGprinterPlatform.instance.connectNet(ipAddress);
  }

  void connectBt(String macAddress) {
    FlutterGprinterPlatform.instance.connectBt(macAddress);
  }

  Future<bool> write(List<int> bytes) {
    return FlutterGprinterPlatform.instance.write(bytes);
  }

  void connect(String token, SocketDataHandler handler) {
    final wsUrl = Uri.parse('wss://oapi.jarvisgo.cn/ws/im/$token');
    var channel = WebSocketChannel.connect(wsUrl);

    channel.stream.listen((response) {
      handler(response);
    });
  }

  void disconnect() {
    FlutterGprinterPlatform.instance.disconnect();
  }

  Future<void> addPrintTask(List<int> commands) async {
    RootIsolateToken token = RootIsolateToken.instance!;
    worker.sendMessage(PrintEvent(token, commands));
  }

  void dispose() {
    worker.dispose();
  }
}

class PrintEvent {
  PrintEvent(this.token, this.commands);

  final RootIsolateToken token;

  final List<int> commands;
}
